package com.mas.user;

import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.OneShotBehaviour;
import jade.core.behaviours.TickerBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.swing.JOptionPane;

import com.mas.common.AgentUtil;
import com.mas.common.Consts;
import com.mas.resource.ResourceInfo;
import com.mas.session.Session;
import com.mas.session.UserSession;
import com.mas.strategey.Proposal;

@SuppressWarnings("serial")
public class UserResourceAgent extends Agent {
	// The list of known seller agents
	private AID[] sellerAgents;
	private UserResourceAgentGui userResourceAgentGui;
	private Map<String, Session> mapSession;
	private boolean done;
	private int uniqueID;

	// Put agent initializations here
	protected void setup() {
		mapSession = new HashMap<String, Session>();
		setDone(false);
		uniqueID = 0;
		userResourceAgentGui = new UserResourceAgentGui(this);
		userResourceAgentGui.show();

		addBehaviour(new DescFalicitatorFinder(this, Consts.DescFalicitatorFinderInterval_msec));
	}

	// Put agent clean-up operations here
	protected void takeDown() {
		AgentUtil.logInfo(this, "Done");
	}

	public class RequestPerformer extends OneShotBehaviour {

		private Proposal proposal;
		private AID monitorAgentID;

		public RequestPerformer(Proposal proposal, AID monitorAgentID) {
			super();
			this.proposal = proposal;
			this.monitorAgentID = monitorAgentID;
		}

		public void action() {
			uniqueID++;
			String sessionName = myAgent.getLocalName() + "<->"
					+ monitorAgentID.getLocalName() + ":" + uniqueID;
			Map<String, Double> mapInitPrices = buildInitPrices(proposal.getResourceInfos());
			UserSession session = new UserSession((UserResourceAgent) myAgent,
					sessionName, mapInitPrices);
			mapSession.put(monitorAgentID.getName(), session);

			myAgent.addBehaviour(new UserAgentSessionBehaviour(session,
					monitorAgentID, proposal));

		}

		private Map<String, Double> buildInitPrices(ResourceInfo[] resourceInfos) {
			Map<String, Double> mapInitPrices = new HashMap<String, Double>();
			for (int i = 0; i < resourceInfos.length; i++) {
				ResourceInfo resourceInfo = resourceInfos[i];
				mapInitPrices.put(resourceInfo.getResourceName(), resourceInfo
						.getPrice());
			}
			return mapInitPrices;
		}

	}

	public void startNegotiate(List<ResourceInfo> resourceList)
			throws Exception {

		if (sellerAgents == null || sellerAgents.length == 0) {
			// throw new Exception("No monitor found,please try later");
			displyError("No monitor found,please try later");
			return;
		}
		clearInactiveSession();

		resourceList.toArray();
		ResourceInfo[] resourceInfos = new ResourceInfo[resourceList.size()];
		resourceList.toArray(resourceInfos);

		for (int j = 0; j < sellerAgents.length; ++j) {
			if (!mapSession.containsKey(sellerAgents[j].getName())) {

				Proposal proposal = buildProposal(resourceInfos);
				this.addBehaviour(new RequestPerformer(proposal,
						sellerAgents[j]));
			}
		}

	}

	private void clearInactiveSession() {
		for (Entry<String, Session> entry : mapSession.entrySet()) {
			if (!entry.getValue().isAliveInd())
				mapSession.remove(entry.getKey());
		}

	}

	private Proposal buildProposal(ResourceInfo[] resourceInfos) {
		ResourceInfo[] resourceInfosCopy = new ResourceInfo[resourceInfos.length];
		System.arraycopy(resourceInfos, 0, resourceInfosCopy, 0,
				resourceInfos.length);
		Proposal proposal = new Proposal();
		proposal.setResourceInfos(resourceInfos);
		return proposal;
	}

	public void displyError(String message) {
		JOptionPane.showMessageDialog(this.userResourceAgentGui, message,
				"Error", JOptionPane.ERROR_MESSAGE);
	}

	public void displyMsg(String message) {
		JOptionPane.showMessageDialog(this.userResourceAgentGui, message,
				"Please note...", JOptionPane.INFORMATION_MESSAGE);
	}

	/**
	 * @param done
	 *            the done to set
	 */
	public void setDone(boolean done) {
		this.done = done;
	}

	/**
	 * @return the done
	 */
	public boolean isDone() {
		return done;
	}

	class DescFalicitatorFinder extends TickerBehaviour {

		public DescFalicitatorFinder(Agent a, long period) {
			super(a, period);
		}

		protected void onTick() {
			AgentUtil.logInfo(myAgent, "Searching for Resource Monitor Agents");
			// Update the list of seller agents
			DFAgentDescription template = new DFAgentDescription();
			ServiceDescription sd = new ServiceDescription();

			sd.setType(Consts.AgentType_Monitor);
			sd.setName(Consts.AgentName_Monitor);
			template.addServices(sd);
			try {
				DFAgentDescription[] result = DFService.search(myAgent,
						template);
				sellerAgents = new AID[result.length];
				for (int i = 0; i < result.length; ++i) {
					sellerAgents[i] = result[i].getName();
					AgentUtil.logInfo(myAgent,
							"Finding Resource Monitor Agent:"
									+ result[i].getName());
				}
			} catch (FIPAException fe) {
				fe.printStackTrace();
			}

			// if (session != null && !session.isAliveInd()) {
			// AgentUtil.logInfo(myAgent, "Agent Exit... bye");
			// doDelete();
			// }
		}
	}

}
